home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / sendmail / sendmail-5.65c+IDA-1.4.4.1 / src / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-08-06  |  30.2 KB  |  1,386 lines

  1. /*
  2.  * Copyright (c) 1983 Eric P. Allman
  3.  * Copyright (c) 1988 Regents of the University of California.
  4.  * All rights reserved.
  5.  *
  6.  * Redistribution and use in source and binary forms are permitted provided
  7.  * that: (1) source distributions retain this entire copyright notice and
  8.  * comment, and (2) distributions including binaries display the following
  9.  * acknowledgement:  ``This product includes software developed by the
  10.  * University of California, Berkeley and its contributors'' in the
  11.  * documentation or other materials provided with the distribution and in
  12.  * all advertising materials mentioning features or use of this software.
  13.  * Neither the name of the University nor the names of its contributors may
  14.  * be used to endorse or promote products derived from this software without
  15.  * specific prior written permission.
  16.  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
  17.  * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
  18.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  19.  */
  20.  
  21. #ifndef lint
  22. # define IN_SCCS_ID
  23. # define _DEFINE
  24. char copyright[] =
  25. "@(#) Copyright (c) 1988 Regents of the University of California.\n\
  26.  All rights reserved.\n";
  27. static char sccsid[] = "@(#)main.c    5.31 (Berkeley) 7/20/90";
  28. static char  rcsid[] = "@(#)$Id: main.c,v 5.29.0.36 1991/08/06 18:17:12 paul Exp $";
  29. # ifdef    __GNUC__
  30. static    char    compiled[] = "@(#)compiled by gcc version "__VERSION__;
  31. # endif    /* __GNUC__ */
  32. #endif /* not lint */
  33.  
  34. #ifdef AIX
  35. # include <sys/utsname.h>
  36. # undef newstr    /* a structure name in sys/utsname.h under RT/AIX */
  37. #endif /* AIX */
  38. #include "sendmail.h"
  39. #if defined(HAS_UNAME) && !defined(AIX)
  40. # include <sys/utsname.h>
  41. #endif /* HAS_UNAME && !AIX */
  42. #include <sgtty.h>
  43. #ifdef NAMED_BIND
  44. # include <arpa/nameser.h>
  45. # include <resolv.h>
  46. #endif /* NAMED_BIND */
  47. #ifndef MAXHOSTNAMELEN
  48. # define MAXHOSTNAMELEN    64
  49. #endif /* !MAXHOSTNAMELEN */
  50.  
  51. #ifdef lint
  52. int    edata, end;
  53. #endif /* lint */
  54.  
  55. #ifdef __STDC__
  56. static SIG_TYPE intsig();
  57. static void initmacros();
  58. static void freeze(char *);
  59. static thaw(char *);
  60. #else /* !__STDC__ */
  61. static SIG_TYPE intsig();
  62. static void initmacros();
  63. static void freeze();
  64. static thaw();
  65. #endif /* __STDC__ */
  66.  
  67. /*
  68. **  SENDMAIL -- Post mail to a set of destinations.
  69. **
  70. **    This is the basic mail router.  All user mail programs should
  71. **    call this routine to actually deliver mail.  Sendmail in
  72. **    turn calls a bunch of mail servers that do the real work of
  73. **    delivering the mail.
  74. **
  75. **    Sendmail is driven by tables read in from /usr/lib/sendmail.cf
  76. **    (read by readcf.c).  Some more static configuration info,
  77. **    including some code that you may want to tailor for your
  78. **    installation, is in conf.c.  You may also want to touch
  79. **    daemon.c (if you have some other IPC mechanism), acct.c
  80. **    (to change your accounting), names.c (to adjust the name
  81. **    server mechanism).
  82. **
  83. **    Usage:
  84. **        /usr/lib/sendmail [flags] addr ...
  85. **
  86. **        See the associated documentation for details.
  87. **
  88. **    Author:
  89. **        Eric Allman, UCB/INGRES (until 10/81)
  90. **                 Britton-Lee, Inc., purveyors of fine
  91. **                database computers (from 11/81)
  92. **        The support of the INGRES Project and Britton-Lee is
  93. **            gratefully acknowledged.  Britton-Lee in
  94. **            particular had absolutely nothing to gain from
  95. **            my involvement in this project.
  96. */
  97.  
  98.  
  99. int        NextMailer;    /* "free" index into Mailer struct */
  100. char        *FullName;    /* sender's full name */
  101. char        *MatchRecipient;/* for selective queue runs on Recipients */
  102. char        *MatchSender;    /* for selective queue runs on Senders */
  103. char        *QueueID;    /* run a certain message in the queue */
  104. ENVELOPE    BlankEnvelope;    /* a "blank" envelope */
  105. ENVELOPE    MainEnvelope;    /* the envelope around the basic letter */
  106. ADDRESS        NullAddress =    /* a null address */
  107.         { "", "", NULL, "" };
  108.  
  109. /*
  110. **  Pointers for setproctitle.
  111. **    This allows "ps" listings to give more useful information.
  112. **    These must be kept out of BSS for frozen configuration files
  113. **        to work.
  114. */
  115.  
  116. #ifdef SETPROCTITLE
  117. char        **Argv = NULL;        /* pointer to argument vector */
  118. char        *LastArgv = NULL;    /* end of argv */
  119. #endif /* SETPROCTITLE */
  120.  
  121. #ifdef DAEMON
  122. # ifndef SMTP
  123. ERROR %%%%   Cannot have daemon mode without SMTP   %%%% ERROR
  124. # endif /* SMTP */
  125. #endif /* DAEMON */
  126.  
  127. void
  128. main(argc, argv, envp)
  129.     int argc;
  130.     char **argv;
  131.     char **envp;
  132. {
  133.     register char *p;
  134.     char **av;
  135.     extern char Version[];
  136.     char *from;
  137.     typedef int (*fnptr)();
  138.     STAB *st;
  139.     register int i;
  140.     bool readconfig = TRUE;
  141.     bool queuemode = FALSE;        /* process queue requests */
  142.     bool NoName = FALSE;
  143.     bool nothaw;
  144.     static bool reenter = FALSE;
  145.     char jbuf[MAXHOSTNAMELEN+1];    /* holds MyHostName */
  146. #if defined(SETPROCTITLE) && !defined(SYSV)
  147.     char *UserEnviron[MAXUSERENVIRON+1];    /* saved user environment */
  148.     extern char **environ;
  149. #endif /* SETPROCTITLE && !SYSV */
  150.  
  151.     /*
  152.     **  Check to see if we reentered.
  153.     **    This would normally happen if e_putheader or e_putbody
  154.     **    were NULL when invoked.
  155.     */
  156.  
  157.     if (reenter)
  158.     {
  159.         syserr("main: reentered!");
  160.         abort();
  161.     }
  162.     reenter = TRUE;
  163.  
  164. #if defined(notdef) && !defined(SYSV)
  165.     /* Enforce use of local time */
  166.     (void) unsetenv("TZ");
  167. #endif /* notdef && !SYSV */
  168.  
  169.     /* Make mail act uniformly (resolver recursion disabled elsewhere) */
  170.     (void) unsetenv("HOSTALIASES");
  171.     (void) unsetenv("LOCALDOMAIN");
  172.  
  173.     /*
  174.     **  Be sure we have enough file descriptors.
  175.     **    But also be sure that 0, 1, & 2 are open.
  176.     */
  177.  
  178.     i = open("/dev/null", O_RDWR);
  179.     while (i >= 0 && i < 2)
  180.         i = dup(i);
  181. #if defined(XPG3)
  182.     for (i = (int) sysconf (_SC_OPEN_MAX); i > 2; --i)
  183. #else /* !XPG3 */
  184.     for (i = getdtablesize(); i > 2; --i)
  185. #endif /* XPG3 */
  186.         (void) close(i);
  187.     errno = 0;
  188.  
  189. #ifdef LOG
  190. # ifdef LOG_MAIL
  191.     openlog("sendmail", LOG_PID, LOG_MAIL);
  192. # else /* !LOG_MAIL */
  193.     openlog("sendmail", LOG_PID);
  194. # endif /* LOG_MAIL */
  195. #endif /* LOG */
  196.  
  197.     /*
  198.     **  Set default values for variables.
  199.     **    These cannot be in initialized data space.
  200.     */
  201.  
  202.     setdefaults();
  203.  
  204.     /* set up the blank envelope */
  205.     BlankEnvelope.e_puthdr = putheader;
  206.     BlankEnvelope.e_putbody = putbody;
  207.     BlankEnvelope.e_xfp = NULL;
  208.     STRUCTCOPY(NullAddress, BlankEnvelope.e_from);
  209.     CurEnv = &BlankEnvelope;
  210.     STRUCTCOPY(NullAddress, MainEnvelope.e_from);
  211.  
  212.     argv[argc] = NULL;
  213.     av = argv;
  214.     nothaw = FALSE;
  215.  
  216.     /*
  217.     **  Do a quick prescan of the argument list.
  218.     **    We do this to find out if we can potentially thaw the
  219.     **    configuration file.  If not, we do the thaw now so that
  220.     **    the argument processing applies to this run rather than
  221.     **    to the run that froze the configuration.
  222.     */
  223.     while ((p = *++av) != NULL)
  224.     {
  225.         if (strncmp(p, "-C", 2) == 0)
  226.         {
  227.             ConfFile = &p[2];
  228.             if (ConfFile[0] == '\0')
  229.                 ConfFile = "sendmail.cf";
  230.             (void) setgid(getrgid());
  231.             (void) setuid(getruid());
  232.             nothaw = TRUE;
  233.         }
  234.         else if (strncmp(p, "-bz", 3) == 0)
  235.             nothaw = TRUE;
  236.         else if (strncmp(p, "-bd", 3) == 0 || strncmp(p, "-q", 2) == 0)
  237.             NoName = TRUE;
  238.         else if (strncmp(p, "-Z", 2) == 0)
  239.         {
  240. #ifdef _PATH_SENDMAILFC
  241.             FreezeFile = &p[2];
  242.             if (FreezeFile[0] == '\0')
  243.                 FreezeFile = "sendmail.fc";
  244.             (void) setgid(getrgid());
  245.             (void) setuid(getruid());
  246. #else /* !_PATH_SENDMAILFC */
  247.             /* Use printf since OutChannel isn't assigned yet */
  248.             printf("Frozen configuration files not available\n");
  249. #endif /* _PATH_SENDMAILFC */
  250.         }
  251.         else if (strncmp(p, "-d", 2) == 0)
  252.         {
  253.             tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
  254.             tTflag(&p[2]);
  255. #if defined(XPG3)
  256.             setvbuf(stdout, (char *) NULL, _IOLBF, BUFSIZ);
  257. #else /* !XPG3 */
  258. # if defined(SYSV)
  259.             setbuf(stdout, (char *)NULL);
  260. # else /* !SYSV */
  261.             setlinebuf(stdout);
  262. # endif /* SYSV */
  263. #endif /* XPG3 */
  264.             printf("Version %s\n", Version);
  265.         }
  266.     }
  267.  
  268.     InChannel = stdin;
  269.     OutChannel = stdout;
  270.  
  271.     /*
  272.      * Copy the environment only if a successful thaw() is done
  273.      * and/or the environment will be munged later by setproctitle().
  274.      */
  275. #ifdef _PATH_SENDMAILFC
  276.     if (!nothaw)
  277.         readconfig = !thaw(FreezeFile);
  278. #endif /* _PATH_SENDMAILFC */
  279.  
  280. #if defined(SETPROCTITLE) && !defined(SYSV)
  281.     for (i = 0; i < MAXUSERENVIRON && envp[i] != NULL; i++)
  282.         UserEnviron[i] = newstr(envp[i]);
  283.     UserEnviron[i] = NULL;
  284.     environ = UserEnviron;
  285.  
  286.     /*
  287.     **  Save start and extent of argv for setproctitle.
  288.     */
  289.  
  290.     Argv = argv;
  291.     if (i > 0)
  292.         LastArgv = envp[i - 1] + strlen(envp[i - 1]);
  293.     else
  294.         LastArgv = argv[argc - 1] + strlen(argv[argc - 1]);
  295. #endif /* SETPROCTITLE && !SYSV */
  296.  
  297. #ifdef NAMED_BIND
  298.     /*
  299.     ** Make sure the resolver library is initialized and that enough time
  300.     ** is allowed for non-local servers.
  301.     */
  302.     res_init();
  303.     _res.retrans = 30;
  304. #endif /* NAMED_BIND */
  305.  
  306.     if (signal(SIGINT, SIG_IGN) != (SIG_TYPE (*)()) SIG_IGN)
  307.         (void) signal(SIGINT, intsig);
  308.     if (signal(SIGHUP, SIG_IGN) != (SIG_TYPE (*)()) SIG_IGN)
  309.         (void) signal(SIGHUP, intsig);
  310.     (void) signal(SIGTERM, intsig);
  311.     (void) signal(SIGPIPE, SIG_IGN);
  312.     OldUmask = umask(0);
  313.     OpMode = MD_DELIVER;
  314.     MotherPid = getpid();
  315.     srand(MotherPid);
  316.     FullName = (NoName) ? NULL : getenv("NAME");
  317.  
  318.     errno = 0;
  319.     from = NULL;
  320.  
  321.     if (readconfig)
  322.     {
  323.         /* initialize some macros, etc. */
  324.         initmacros();
  325.  
  326.         /* hostname */
  327.         av = myhostname(jbuf, sizeof jbuf);
  328.         if (jbuf[0] != '\0')
  329.         {
  330. #ifdef HAS_UNAME
  331.             struct    utsname    utsname;
  332. #endif /* HAS_UNAME */
  333.             if (tTd(0, 4))
  334.                 printf("canonical name: %s\n", jbuf);
  335.             p = newstr(jbuf);
  336.             define('w', p, CurEnv);
  337.             setclass('w', p);
  338.             if ((p = index(jbuf, '.')) != NULL)
  339.                 *p = '\0';
  340.             makelower(jbuf);
  341. #ifdef HAS_UNAME
  342.             if ((uname(&utsname) != -1) &&
  343.                 strncmp(utsname.nodename, jbuf, 8))
  344.             {
  345.                 define('k', newstr(utsname.nodename), CurEnv);
  346.                 if (tTd(0, 4))
  347.                     printf("UUCP nodename: %s\n",
  348.                         utsname.nodename);
  349.             }
  350.             else
  351. #endif /* HAS_UNAME */
  352.             define('k', newstr(jbuf), CurEnv);
  353.         }
  354.         while (av != NULL && *av != NULL)
  355.         {
  356.             if (tTd(0, 4))
  357.                 printf("\ta.k.a.: %s\n", *av);
  358.             setclass('w', *av++);
  359.         }
  360.  
  361.         /* version */
  362.         define('v', Version, CurEnv);
  363.     }
  364.  
  365.     /* current time */
  366.     define('b', arpadate((char *) NULL), CurEnv);
  367.  
  368.     /*
  369.     ** Crack argv.
  370.     */
  371.  
  372.     av = argv;
  373.     p = rindex(*av, '/');
  374.     if (p++ == NULL)
  375.         p = *av;
  376.     if (strcmp(p, "newaliases") == 0)
  377.         OpMode = MD_INITALIAS;
  378.     else if (strcmp(p, "mailq") == 0)
  379.         OpMode = MD_PRINT;
  380.     else if (strcmp(p, "smtpd") == 0)
  381.         OpMode = MD_DAEMON;
  382.     else if (strcmp(p, "bsmtp") == 0)
  383.         OpMode = MD_BSMTP;
  384.     while ((p = *++av) != NULL && p[0] == '-')
  385.     {
  386.         switch (p[1])
  387.         {
  388.           case 'b':    /* operations mode */
  389.             switch (p[2])
  390.             {
  391.               case MD_DAEMON:
  392. #ifdef DAEMON
  393.                 if (getuid() != 0)
  394.                 {
  395.                     usrerr("Permission denied");
  396.                     exit (EX_USAGE);
  397.                 }
  398. #else /* !DAEMON */
  399.                 usrerr("Daemon mode not implemented");
  400.                 ExitStat = EX_USAGE;
  401.                 break;
  402. #endif /* DAEMON */
  403.               case MD_SMTP:
  404.               case MD_BSMTP:
  405. #ifndef SMTP
  406.                 usrerr("I don't speak SMTP");
  407.                 ExitStat = EX_USAGE;
  408.                 break;
  409. #endif /* SMTP */
  410.               case MD_ARPAFTP:
  411.               case MD_DELIVER:
  412.               case MD_VERIFY:
  413.               case MD_TEST:
  414.               case MD_INITALIAS:
  415.               case MD_PRINT:
  416.               case MD_FREEZE:
  417.                 OpMode = p[2];
  418.                 break;
  419.  
  420.               default:
  421.                 usrerr("Invalid operation mode %c", p[2]);
  422.                 ExitStat = EX_USAGE;
  423.                 break;
  424.             }
  425.             break;
  426.  
  427.           case 'C':    /* select configuration file (already done) */
  428.             break;
  429.  
  430.           case 'Z':    /* select frozen config file (already done) */
  431.             break;
  432.  
  433.           case 'd':    /* debugging -- redo in case frozen */
  434.             tTsetup(tTdvect, sizeof tTdvect, "0-99.1");
  435.             tTflag(&p[2]);
  436.             tTflag(&p[2]);
  437. #if defined(XPG3)
  438.             setvbuf(stdout, (char *) NULL, _IOLBF, BUFSIZ);
  439. #else /* !XPG3 */
  440. # if defined(SYSV)
  441.             setbuf(stdout, (char *)NULL);
  442. # else /* !SYSV */
  443.             setlinebuf(stdout);
  444. # endif /* SYSV */
  445. #endif /* XPG3 */
  446. #ifdef NAMED_BIND
  447.             if (tTd(8, 8))
  448.             _res.options |= RES_DEBUG;
  449. #endif /* NAMED_BIND */
  450.             break;
  451.  
  452.           case 'f':    /* from address */
  453.           case 'r':    /* obsolete -f flag */
  454.             p += 2;
  455.             if (*p == '\0' && ((p = *++av) == NULL || *p == '-'))
  456.             {
  457.                 p = *++av;
  458.                 if (p == NULL || *p == '-')
  459.                 {
  460.                     usrerr("No \"from\" person");
  461.                     ExitStat = EX_USAGE;
  462.                     av--;
  463.                     break;
  464.                 }
  465.             }
  466.             if (from != NULL)
  467.             {
  468.                 usrerr("More than one \"from\" person");
  469.                 ExitStat = EX_USAGE;
  470.                 break;
  471.             }
  472.             from = newstr(p);
  473.             break;
  474.  
  475.           case 'F':    /* set full name */
  476.             p += 2;
  477.             if (*p == '\0' && ((p = *++av) == NULL || *p == '-'))
  478.             {
  479.                 usrerr("Bad -F flag");
  480.                 ExitStat = EX_USAGE;
  481.                 av--;
  482.                 break;
  483.             }
  484.             FullName = newstr(p);
  485.             break;
  486.  
  487.           case 'h':    /* hop count */
  488.             p += 2;
  489.             if (*p == '\0' && ((p = *++av) == NULL || !isdigit(*p)))
  490.             {
  491.                 usrerr("Bad hop count (%s)", p);
  492.                 ExitStat = EX_USAGE;
  493.                 av--;
  494.                 break;
  495.             }
  496.             CurEnv->e_hopcount = atoi(p);
  497.             break;
  498.         
  499.           case 'n':    /* don't alias */
  500.             NoAlias = TRUE;
  501.             break;
  502.  
  503.           case 'o':    /* set option */
  504.             setoption(p[2], &p[3], FALSE, TRUE);
  505.             break;
  506.  
  507.           case 'q':    /* run queue files at intervals */
  508.           case 'R':    /* run queued messages matching pattern */
  509.           case 'S':    /* run queued messages matching pattern */
  510.           case 'M':    /* run queue message with this queue ID */
  511.                 /* or if 'a' < p[2] <= 'z', set the macro */
  512.                 /* this is worse than hideous, blame DECnet */
  513.             if (p[1] == 'M' && p[2] != '\0' && islower(p[2]) &&
  514.                 p[2] > 'a')
  515.             {
  516.                 setoption(p[1], &p[2], FALSE, TRUE);
  517.                 break;
  518.             }
  519. #ifdef QUEUE
  520.           {
  521.             char c = p[1];
  522.  
  523.             p += 2;
  524.             if (getuid() != 0)
  525.             {
  526.                 usrerr("Permission denied");
  527.                 exit (EX_USAGE);
  528.             }
  529.             if (queuemode)
  530.             {
  531.                     usrerr("Use only one of -q, -R, -S, and -M");
  532.                 exit (EX_USAGE);
  533.             }
  534.             if (c != 'q')
  535.             {
  536.                 if (*p == '\0' && ((p = *++av) == NULL || 
  537.                     *p == '-'))
  538.                 {
  539.                     usrerr("Bad -%c flag", c);
  540.                     ExitStat = EX_USAGE;
  541.                     av--;
  542.                     break;
  543.                 }
  544.             }
  545.             queuemode = TRUE;
  546.             switch (c)
  547.             {
  548.               case 'q':
  549.                 QueueIntvl = convtime(p);
  550.                 break;
  551.  
  552.               case 'R':
  553.                 MatchRecipient = newstr(p);
  554.                 break;
  555.  
  556.               case 'S':
  557.                 MatchSender = newstr(p);
  558.                 break;
  559.  
  560.               case 'M':
  561.                 QueueID = newstr(p);
  562.                 break;
  563.             }
  564.           }
  565. #else /* !QUEUE */
  566.             usrerr("I don't know about queues");
  567.             ExitStat = EX_USAGE;
  568. #endif /* QUEUE */
  569.             break;
  570.  
  571.           case 't':    /* read recipients from message */
  572.             GrabTo = TRUE;
  573.             break;
  574.  
  575.             /* compatibility flags */
  576.           case 'c':    /* connect to non-local mailers */
  577.           case 'e':    /* error message disposition */
  578.           case 'i':    /* don't let dot stop me */
  579.           case 'm':    /* send to me too */
  580.           case 'T':    /* set timeout interval */
  581.           case 'v':    /* give blow-by-blow description */
  582.             setoption(p[1], &p[2], FALSE, TRUE);
  583.             break;
  584.  
  585.           case 's':    /* save From lines in headers */
  586.             setoption('f', &p[2], FALSE, TRUE);
  587.             break;
  588.  
  589. #ifdef DBM
  590.           case 'I':    /* initialize alias DBM file */
  591.             OpMode = MD_INITALIAS;
  592.             break;
  593. #endif /* DBM */
  594.         }
  595.     }
  596.  
  597.     /*
  598.     **  Do basic initialization.
  599.     **    Read system control file.
  600.     **    Extract special fields for local use.
  601.     */
  602.  
  603. #ifdef BIT8
  604.     {
  605.         char    *abuf = newstr("ASCII");
  606.         ascii = getchset(abuf, 29);
  607.         free(abuf);
  608.     }
  609. #endif /* BIT8 */
  610.  
  611.     if (OpMode == MD_FREEZE || readconfig)
  612.         readcf(ConfFile);
  613.  
  614.     switch (OpMode)
  615.     {
  616.       case MD_FREEZE:
  617. #ifdef _PATH_SENDMAILFC
  618.         /* this is critical to avoid forgeries of the frozen config */
  619.         (void) setgid(getgid());
  620.         (void) setuid(getuid());
  621.  
  622.         /* freeze the configuration */
  623.         freeze(FreezeFile);
  624.         exit(EX_OK);
  625. #else /* !_PATH_SENDMAILFC */
  626.         usrerr("Frozen configuration files not available");
  627.         exit(EX_USAGE);
  628. #endif /* _PATH_SENDMAILFC */
  629.  
  630.       case MD_INITALIAS:
  631.         Verbose = TRUE;
  632.         break;
  633.     }
  634.  
  635. #ifdef notdef
  636.     /*
  637.      * Print the argument list when debugging.  This has to come after the
  638.      * freeze() statement as the first syslog() call sets a state variable
  639.      * that won't get saved or restored.
  640.      */
  641.     {
  642.         char    *cmdline = xalloc(MAXLINE);
  643.  
  644.         for (*cmdline = '\0', av = argv; *av; av++)
  645.         {
  646.             (void) strcat(cmdline, *av);
  647.             (void) strcat(cmdline, " ");
  648.         }
  649.         syslog(LOG_DEBUG, "Invoked as: %s", cmdline);
  650.         free(cmdline);
  651.     }
  652. #endif /* notdef */
  653.  
  654.     /*
  655.      *    The call to setdefuser() is moved from readcf.c to here.
  656.      *    The result is only used in deliver.c, so delaying it until
  657.      *    now should be safe.
  658.      *
  659.      *    The function setdefuser() looks up the passwd database.  In
  660.      *    some systems, notably Suns, this may involve a YP lookup.
  661.      *    Unfortunately YP lookups leave behind some state information
  662.      *    which seems to be incompatible with the freeze/thaw operations.
  663.      *
  664.      *    Placing the call here delays it till after the freeze/thaw
  665.      *    is complete.
  666.      */
  667.     setdefuser();
  668.  
  669.     /* do heuristic mode adjustment */
  670.     if (Verbose)
  671.     {
  672.         /* turn off noconnect option */
  673.         setoption('c', "F", TRUE, FALSE);
  674.  
  675.         /* turn on interactive delivery */
  676.         setoption('d', "", TRUE, FALSE);
  677.     }
  678.  
  679.     /* our name for SMTP codes */
  680.     expand("\001j", jbuf, &jbuf[sizeof jbuf - 1], CurEnv);
  681.     MyHostName = jbuf;
  682.  
  683.     /* the indices of local and program mailers */
  684.     st = stab("local", ST_MAILER, ST_FIND);
  685.     if (st == NULL)
  686.         syserr("No local mailer defined");
  687.     else
  688.         LocalMailer = st->s_mailer;
  689.     st = stab("prog", ST_MAILER, ST_FIND);
  690.     if (st == NULL)
  691.         syserr("No prog mailer defined");
  692.     else
  693.         ProgMailer = st->s_mailer;
  694.  
  695.     /* operate in queue directory */
  696.     if (chdir(QueueDir) < 0)
  697.     {
  698.         syserr("cannot chdir(%s)", QueueDir);
  699.         exit(EX_SOFTWARE);
  700.     }
  701.  
  702.     /*
  703.     **  Do operation-mode-dependent initialization.
  704.     */
  705.  
  706.     switch (OpMode)
  707.     {
  708.       case MD_PRINT:
  709.         /* print the queue */
  710. #ifdef QUEUE
  711.         dropenvelope(CurEnv);
  712.         printqueue();
  713.         exit(EX_OK);
  714. #else /* !QUEUE */
  715.         usrerr("No queue to print");
  716.         finis();
  717. #endif /* QUEUE */
  718.  
  719.       case MD_INITALIAS:
  720.         /* initialize alias database */
  721.         initaliases(TRUE);
  722.         exit(EX_OK);
  723.  
  724.       case MD_DAEMON:
  725.         /* don't open alias database -- done in srvrsmtp */
  726.         break;
  727.  
  728.       default:
  729. #if !defined(DBM_AUTOBUILD) || ( !defined(NDBM) && !defined(OTHERDBM) )
  730.         /* open the alias database */
  731.         initaliases(FALSE);
  732. #endif /* !DBM_AUTOBUILD || (!NDBM && !OTHERDBM) */
  733.         break;
  734.     }
  735.  
  736.     if (tTd(0, 15))
  737.     {
  738.         /* print configuration table (or at least part of it) */
  739.         printrules();
  740.         for (i = 0; i < MAXMAILERS; i++)
  741.         {
  742.             register struct mailer *m = Mailer[i];
  743.             int j;
  744.  
  745.             if (m == NULL)
  746.                 continue;
  747.             printf("mailer %d (%s): P=%s S=%d/%d R=%d/%d M=%ld F=",
  748.                 i, m->m_name, m->m_mailer,
  749.                 m->m_se_rwset, m->m_sh_rwset,
  750.                 m->m_re_rwset, m->m_rh_rwset, m->m_maxsize);
  751.             for (j = '\0'; j <= '\177'; j++)
  752.                 if (bitnset(j, m->m_flags))
  753.                     (void) putchar(j);
  754.             printf(" E=");
  755.             xputs(m->m_eol);
  756.             printf("\n");
  757.         }
  758.     }
  759.  
  760.     /*
  761.     **  Switch to the main envelope.
  762.     */
  763.  
  764.     CurEnv = newenvelope(&MainEnvelope);
  765.     MainEnvelope.e_flags = BlankEnvelope.e_flags;
  766.  
  767.     if (tTd(3, 1))
  768.         (void) getla();    /* prints load average in getla() */
  769.  
  770.     /*
  771.     **  If test mode, read addresses from stdin and process.
  772.     */
  773.  
  774.     if (OpMode == MD_TEST)
  775.     {
  776.         char buf[MAXLINE];
  777.  
  778.         printf("ADDRESS TEST MODE\nEnter <ruleset> <address>\n");
  779.         printf("[Note: No initial ruleset 3 call]\n");
  780.         for (;;)
  781.         {
  782.             register char **pvp;
  783.             char *q;
  784.             extern char *DelimChar;
  785.  
  786.             printf("> ");
  787.             (void) fflush(stdout);
  788.             if (fgets(buf, sizeof buf, stdin) == NULL)
  789.                 finis();
  790.             for (p = buf; isspace(*p); p++)
  791.                 continue;
  792.             q = p;
  793.             while (*p != '\0' && !isspace(*p))
  794.                 p++;
  795.             if (*p == '\0')
  796.                 continue;
  797.             *p = '\0';
  798.             if (invalidaddr(p+1))
  799.                 continue;
  800.             do
  801.             {
  802.                 char pvpbuf[PSBUFSIZE];
  803.  
  804.                 pvp = prescan(++p, '\0', pvpbuf);
  805.                 if (pvp == NULL)
  806.                     continue;
  807.                 /* rewrite(pvp, 3); */
  808.                 p = q;
  809.                 while (*p != '\0')
  810.                 {
  811.                     rewrite(pvp, atoi(p));
  812.                     while (*p != '\0' && *p++ != ',')
  813.                         continue;
  814.                 }
  815.             } while (*(p = DelimChar) != '\0');
  816.         }
  817.     }
  818.  
  819. #ifdef QUEUE
  820.     /*
  821.     **  If collecting stuff from the queue, go start doing that.
  822.     */
  823.  
  824.     if (queuemode && OpMode != MD_DAEMON && QueueIntvl == 0)
  825.     {
  826.         runqueue(FALSE);
  827.         finis();
  828.     }
  829. #endif /* QUEUE */
  830.  
  831.     /*
  832.     **  If a daemon, wait for a request.
  833.     **    getrequests will always return in a child.
  834.     **    If we should also be processing the queue, start
  835.     **        doing it in background.
  836.     **    We check for any errors that might have happened
  837.     **        during startup.
  838.     */
  839.  
  840.     if (OpMode == MD_DAEMON || QueueIntvl != 0)
  841.     {
  842.         if (!tTd(0, 1))
  843.         {
  844.             /* put us in background */
  845.             i = fork();
  846.             if (i < 0)
  847.                 syserr("daemon: cannot fork");
  848.             if (i != 0)
  849.                 exit(0);
  850.  
  851.             /* get our pid right */
  852.             MotherPid = getpid();
  853.  
  854.             /* disconnect from our controlling tty */
  855.             disconnect(TRUE);
  856.         }
  857.  
  858. #ifdef QUEUE
  859.         if (queuemode)
  860.         {
  861.             runqueue(TRUE);
  862.             if (OpMode != MD_DAEMON)
  863.                 for (;;)
  864.                     pause();
  865.         }
  866. #endif /* QUEUE */
  867.         dropenvelope(CurEnv);
  868.  
  869. #ifdef DAEMON
  870.         getrequests();
  871.  
  872.         /* at this point we are in a child: reset state */
  873.         OpMode = MD_SMTP;
  874.         (void) newenvelope(CurEnv);
  875.         openxscript(CurEnv);
  876. #endif /* DAEMON */
  877.     }
  878.     
  879. #ifdef SMTP
  880.     /*
  881.     **  If running SMTP protocol, start collecting and executing
  882.     **  commands.  This will never return.
  883.     */
  884.  
  885.     if (OpMode == MD_SMTP || OpMode == MD_BSMTP)
  886.     {
  887.         bool batched = (OpMode == MD_BSMTP);
  888.         OpMode = MD_SMTP;
  889.  
  890.         /* have to run unbuffered or else will lose synchronization */
  891.         if (batched)
  892.             setbuf(InChannel, (char *) NULL);
  893.         smtp(batched);
  894.     }
  895. #endif /* SMTP */
  896.  
  897.     /*
  898.     **  Do basic system initialization and set the sender
  899.     */
  900.  
  901.     initsys();
  902.     setsender(from);
  903.  
  904.     if (OpMode != MD_ARPAFTP && *av == NULL && !GrabTo)
  905.     {
  906.         usrerr("Recipient names must be specified");
  907.  
  908.         /* collect body for UUCP return */
  909.         if (OpMode != MD_VERIFY)
  910.             collect(FALSE);
  911.         finis();
  912.     }
  913.     if (OpMode == MD_VERIFY)
  914.         SendMode = SM_VERIFY;
  915.  
  916.     /*
  917.     **  Scan argv and deliver the message to everyone.
  918.     */
  919.  
  920.     sendtoargv(av);
  921.  
  922.     /* if we have had errors sofar, arrange a meaningful exit stat */
  923.     if (Errors > 0 && ExitStat == EX_OK)
  924.         ExitStat = EX_USAGE;
  925.  
  926.     /*
  927.     **  Read the input mail.
  928.     */
  929.  
  930.     CurEnv->e_to = NULL;
  931.     if (OpMode != MD_VERIFY || GrabTo)
  932.         collect(FALSE);
  933.     errno = 0;
  934.  
  935.     if (tTd(1, 1))
  936.         printf("From person = \"%s\"\n", CurEnv->e_from.q_paddr);
  937.  
  938.     /*
  939.     **  Actually send everything.
  940.     **    If verifying, just ack.
  941.     */
  942.  
  943.     CurEnv->e_from.q_flags |= QDONTSEND;
  944.     CurEnv->e_to = NULL;
  945.     sendall(CurEnv, SM_DEFAULT);
  946.  
  947.     /* collect statistics (done after sendall, since sendall may fork) */
  948.     if (OpMode != MD_VERIFY)
  949.         markstats(CurEnv, (ADDRESS *) NULL);
  950.  
  951.     /*
  952.     ** All done.
  953.     */
  954.  
  955.     finis();
  956. }
  957. /*
  958. **  FINIS -- Clean up and exit.
  959. **
  960. **    Parameters:
  961. **        none
  962. **
  963. **    Returns:
  964. **        never
  965. **
  966. **    Side Effects:
  967. **        exits sendmail
  968. */
  969.  
  970. void
  971. finis()
  972. {
  973.     if (tTd(2, 1))
  974.         printf("\n====finis: stat %d e_flags %o\n", ExitStat, CurEnv->e_flags);
  975.  
  976.     /* clean up temp files */
  977.     CurEnv->e_to = NULL;
  978.     dropenvelope(CurEnv);
  979.  
  980.     /* post statistics */
  981.     poststats(StatFile);
  982.  
  983.     /* and exit */
  984. #ifdef LOG
  985.     if (LogLevel > 11)
  986.         syslog(LOG_DEBUG, "finis, pid=%d", getpid());
  987. #endif /* LOG */
  988.     if (ExitStat == EX_TEMPFAIL)
  989.         ExitStat = EX_OK;
  990.     exit(ExitStat);
  991. }
  992. /*
  993. **  INTSIG -- clean up on interrupt
  994. **
  995. **    This just arranges to exit.  It pessimises in that it
  996. **    may resend a message.
  997. **
  998. **    Parameters:
  999. **        none.
  1000. **
  1001. **    Returns:
  1002. **        none.
  1003. **
  1004. **    Side Effects:
  1005. **        Unlocks the current job.
  1006. */
  1007.  
  1008. static SIG_TYPE
  1009. intsig()
  1010. {
  1011.     FileName = NULL;
  1012.     unlockqueue(CurEnv);
  1013.     exit(EX_OK);
  1014. }
  1015. /*
  1016. **  INITMACROS -- initialize the macro system
  1017. **
  1018. **    This just involves defining some macros that are actually
  1019. **    used internally as metasymbols to be themselves.
  1020. **
  1021. **    Parameters:
  1022. **        none.
  1023. **
  1024. **    Returns:
  1025. **        none.
  1026. **
  1027. **    Side Effects:
  1028. **        initializes several macros to be themselves.
  1029. */
  1030.  
  1031. struct metamac    MetaMacros[] =
  1032. {
  1033.     /* LHS pattern matching characters */
  1034.     '*', MATCHZANY,    '+', MATCHANY,    '-', MATCHONE,    '=', MATCHCLASS,
  1035.     '~', MATCHNCLASS,        '%', MATCHMAP,    '^', MATCHNMAP,        
  1036.  
  1037.     /* these are RHS metasymbols */
  1038.     '#', CANONNET,    '@', CANONHOST,    ':', CANONUSER,    '>', CALLSUBR,
  1039.  
  1040.     /* the conditional operations */
  1041.     '?', CONDIF,    '|', CONDELSE,    '.', CONDFI,
  1042.  
  1043.     /* and finally the hostname and database lookup characters */
  1044.     '[', HOSTBEGIN,    ']', HOSTEND,
  1045.     '(', KEYBEGIN,    ')', KEYEND,
  1046.  
  1047. #ifdef MACVALUE
  1048.     /* run-time macro expansion, not at freeze time */
  1049.     '&', MACVALUE,
  1050. #endif /* MACVALUE */
  1051. #ifdef QUOTE822
  1052.     '!', QUOTE822,    /* quote next macro if RFC822 requires it */
  1053. #endif /* QUOTE822 */
  1054.     '\0'
  1055. };
  1056.  
  1057. static void
  1058. initmacros()
  1059. {
  1060.     register struct metamac *m;
  1061.     char buf[5];
  1062.     register int c;
  1063.  
  1064.     for (m = MetaMacros; m->metaname != '\0'; m++)
  1065.     {
  1066.         buf[0] = m->metaval;
  1067.         buf[1] = '\0';
  1068.         define(m->metaname, newstr(buf), CurEnv);
  1069.     }
  1070.     buf[0] = MATCHREPL;
  1071.     buf[2] = '\0';
  1072.     for (c = '0'; c <= '9'; c++)
  1073.     {
  1074.         buf[1] = c;
  1075.         define(c, newstr(buf), CurEnv);
  1076.     }
  1077. }
  1078.  
  1079. #ifdef _PATH_SENDMAILFC
  1080. /*
  1081. **  FREEZE -- freeze BSS & allocated memory
  1082. **
  1083. **    This will be used to efficiently load the configuration file.
  1084. **
  1085. **    Parameters:
  1086. **        freezefile -- the name of the file to freeze to.
  1087. **
  1088. **    Returns:
  1089. **        none.
  1090. **
  1091. **    Side Effects:
  1092. **        Writes BSS and malloc'ed memory to freezefile
  1093. */
  1094.  
  1095. union frz
  1096. {
  1097.     char        frzpad[BUFSIZ];    /* insure we are on a BUFSIZ boundary */
  1098.     struct
  1099.     {
  1100.         TIME_TYPE frzstamp;    /* timestamp on this freeze */
  1101.         char    *frzbrk;    /* the current break */
  1102.         char    *frzedata;    /* address of edata */
  1103.         char    *frzend;    /* address of end */
  1104.         char    frzver[252];    /* sendmail version */
  1105.         char    frzdatecompiled[64];    /* sendmail compilation date */
  1106.     } frzinfo;
  1107. };
  1108.  
  1109. static void
  1110. freeze(freezefile)
  1111.     char *freezefile;
  1112. {
  1113.     int f;
  1114.     union frz fhdr;
  1115.     extern int edata, end;
  1116. #ifdef __STDC__
  1117.     extern void *sbrk(int);
  1118. #else /* !__STDC__ */
  1119.     extern char *sbrk();
  1120. #endif /* __STDC__ */
  1121.     extern char Version[];
  1122.     extern char datecompiled[];
  1123.  
  1124.     if (freezefile == NULL)
  1125.         return;
  1126. # ifdef notdef
  1127.     {
  1128.         /*
  1129.          * NIS (nee YP) state is saved in the freeze, the readback
  1130.          * of the freeze file destroys similar information.  This
  1131.          * causes strange results later due to the unexpected closing
  1132.          * of a file descriptor using a stale copy.
  1133.          */
  1134.  
  1135.         char *domain;
  1136.         if (yp_get_default_domain(&domain) == 0)
  1137.             yp_unbind(domain);
  1138.     }
  1139. # endif /* YP */
  1140.  
  1141.     /* try to open the freeze file */
  1142.     f = creat(freezefile, FileMode);
  1143.     if (f < 0)
  1144.     {
  1145.         syserr("Cannot freeze %s", freezefile);
  1146.         errno = 0;
  1147.         return;
  1148.     }
  1149.  
  1150.     /* build the freeze header */
  1151.     fhdr.frzinfo.frzstamp = curtime();
  1152.     fhdr.frzinfo.frzbrk = sbrk(0);
  1153.     fhdr.frzinfo.frzedata = (char *) &edata;
  1154.     fhdr.frzinfo.frzend = (char *) &end;
  1155.     (void) strcpy(fhdr.frzinfo.frzver, Version);
  1156.     (void) strcpy(fhdr.frzinfo.frzdatecompiled, datecompiled);
  1157.  
  1158.     /* write out the freeze header */
  1159.     if (write(f, (char *) &fhdr, sizeof fhdr) != sizeof fhdr ||
  1160.         write(f, (char *) &edata, (int) (fhdr.frzinfo.frzbrk - (char *) &edata)) !=
  1161.                     (int) (fhdr.frzinfo.frzbrk - (char *) &edata))
  1162.     {
  1163.         syserr("Cannot freeze %s", freezefile);
  1164.     }
  1165.  
  1166.     /* fine, clean up */
  1167.     (void) close(f);
  1168. }
  1169. /*
  1170. **  THAW -- read in the frozen configuration file.
  1171. **
  1172. **    Parameters:
  1173. **        freezefile -- the name of the file to thaw from.
  1174. **
  1175. **    Returns:
  1176. **        TRUE if it successfully read the freeze file.
  1177. **        FALSE otherwise.
  1178. **
  1179. **    Side Effects:
  1180. **        reads freezefile in to BSS area.
  1181. */
  1182.  
  1183. static int
  1184. thaw(freezefile)
  1185.     char *freezefile;
  1186. {
  1187.     int f;
  1188.     union frz fhdr;
  1189.     extern int edata, end;
  1190.     extern char Version[];
  1191.     extern char datecompiled[];
  1192. #ifdef __STDC__
  1193.     extern int brk(void *);
  1194. #else /* !__STDC__ */
  1195.     extern int brk();
  1196. #endif /* __STDC__ */
  1197.  
  1198.     if (freezefile == NULL)
  1199.         return (FALSE);
  1200.  
  1201.     /* open the freeze file */
  1202.     f = open(freezefile, 0);
  1203.     if (f < 0)
  1204.     {
  1205. # ifdef LOG
  1206.         syslog(LOG_NOTICE, "Cannot open frozen config file %s: %m",
  1207.             freezefile);
  1208. # endif /* LOG */
  1209.         errno = 0;
  1210.         return (FALSE);
  1211.     }
  1212. # ifdef notdef
  1213.     {
  1214.         /*
  1215.          * NIS (nee YP) state is saved in the freeze, the readback
  1216.          * of the freeze file destroys similar information.  This
  1217.          * causes strange results later due to the unexpected closing
  1218.          * of a file descriptor using a stale copy.
  1219.          */
  1220.  
  1221.         char *domain;
  1222.         if (yp_get_default_domain(&domain) == 0)
  1223.             yp_unbind(domain);
  1224.     }
  1225. # endif /* YP */
  1226.  
  1227.     /* read in the header */
  1228.     if (read(f, (char *) &fhdr, sizeof fhdr) < sizeof fhdr)
  1229.     {
  1230.         syserr("Cannot read frozen config file");
  1231.         (void) close(f);
  1232.         return (FALSE);
  1233.     }
  1234.     {
  1235.         char why[40];
  1236.  
  1237.         *why = '\0';
  1238.         if (fhdr.frzinfo.frzedata != (char *) &edata)
  1239.             (void) strcat(why, "Edata");
  1240.         if (fhdr.frzinfo.frzend != (char *) &end)
  1241.             (void) strcat(why, "End");
  1242.         if (strcmp(fhdr.frzinfo.frzver, Version))
  1243.             (void) strcat(why, "Version");
  1244.         if (strcmp(fhdr.frzinfo.frzdatecompiled, datecompiled))
  1245.             (void) strcat(why, "Datecompiled");
  1246.         if (*why)
  1247.         {
  1248.             if (tTd(0, 1))
  1249.                 printf("Wrong version of frozen config file (%s mismatch)\n", why);
  1250. # ifdef LOG
  1251.             syslog(LOG_WARNING, "Wrong version of frozen config file (%s mismatch)", why);
  1252. # endif /* LOG */
  1253.             (void) close(f);
  1254.             return (FALSE);
  1255.         }
  1256.     }
  1257.  
  1258.     /* arrange to have enough space */
  1259.     if (brk(fhdr.frzinfo.frzbrk) == -1)
  1260.     {
  1261.         syserr("Cannot break to %x", fhdr.frzinfo.frzbrk);
  1262.         (void) close(f);
  1263.         return (FALSE);
  1264.     }
  1265.  
  1266.     /* now read in the freeze file */
  1267.     if (read(f, (char *) &edata, (int) (fhdr.frzinfo.frzbrk - (char *) &edata)) !=
  1268.                     (int) (fhdr.frzinfo.frzbrk - (char *) &edata))
  1269.     {
  1270.         syserr("Cannot read frozen config file");
  1271.         /* oops!  we have trashed memory..... */
  1272.         (void) write(2, "Cannot read freeze file\n", 24);
  1273.         _exit(EX_SOFTWARE);
  1274.     }
  1275.  
  1276.     (void) close(f);
  1277.     return (TRUE);
  1278. }
  1279. #endif /* _PATH_SENDMAILFC */
  1280. /*
  1281. **  DISCONNECT -- remove our connection with any foreground process
  1282. **
  1283. **    Parameters:
  1284. **        fulldrop -- if set, we should also drop the controlling
  1285. **            TTY if possible -- this should only be done when
  1286. **            setting up the daemon since otherwise UUCP can
  1287. **            leave us trying to open a dialin, and we will
  1288. **            wait for the carrier.
  1289. **
  1290. **    Returns:
  1291. **        none
  1292. **
  1293. **    Side Effects:
  1294. **        Trys to insure that we are immune to vagaries of
  1295. **        the controlling tty.
  1296. */
  1297.  
  1298. void
  1299. disconnect(fulldrop)
  1300.     bool fulldrop;
  1301. {
  1302.     int fd;
  1303.  
  1304.     if (tTd(52, 1))
  1305.         printf("disconnect: In %d Out %d\n", fileno(InChannel),
  1306.                         fileno(OutChannel));
  1307.     if (tTd(52, 5))
  1308.     {
  1309.         printf("don't\n");
  1310.         return;
  1311.     }
  1312.  
  1313.     /* be sure we don't get nasty signals */
  1314.     (void) signal(SIGHUP, SIG_IGN);
  1315.     (void) signal(SIGINT, SIG_IGN);
  1316.     (void) signal(SIGQUIT, SIG_IGN);
  1317.  
  1318.     /* we can't communicate with our caller, so.... */
  1319.     HoldErrs = TRUE;
  1320.     setoption('e', "m", TRUE, TRUE);
  1321.     Verbose = FALSE;
  1322.  
  1323.     /* all input from /dev/null */
  1324.     if (InChannel != stdin)
  1325.     {
  1326.         (void) fclose(InChannel);
  1327.         InChannel = stdin;
  1328.     }
  1329.     (void) freopen("/dev/null", "r", stdin);
  1330.  
  1331.     /* output to the transcript */
  1332.     if (OutChannel != stdout)
  1333.     {
  1334.         (void) fclose(OutChannel);
  1335.         OutChannel = stdout;
  1336.     }
  1337.     if (CurEnv->e_xfp == NULL)
  1338.         CurEnv->e_xfp = fopen("/dev/null", "w");
  1339.     (void) fflush(stdout);
  1340.     (void) close(1);
  1341.     (void) close(2);
  1342.     while ((fd = dup(fileno(CurEnv->e_xfp))) < 2 && fd > 0)
  1343.         continue;
  1344.  
  1345.     /* drop our controlling TTY completely if possible */
  1346.     if (fulldrop)
  1347.     {
  1348. #if defined(XPG3)
  1349.     /*
  1350.      * setsid will provide a new session w/o any tty associated at all.
  1351.      * STANDARDS CONFORMANCE
  1352.      *     setpgrp: SVID2, XPG2
  1353.      *     setsid: XPG3, POSIX.1, FIPS 151-1
  1354.      */
  1355.     (void) setsid();
  1356. #else /* !XPG3 */
  1357. # if BSD > 43
  1358.         daemon(1, 1);
  1359. # else /* BSD <= 43 */
  1360. #  ifdef TIOCNOTTY
  1361.         fd = open("/dev/tty", 2);
  1362.         if (fd >= 0)
  1363.         {
  1364.             (void) ioctl(fd, (int) TIOCNOTTY, (char *) 0);
  1365.             (void) close(fd);
  1366.         }
  1367.         (void) setpgrp(0, 0);
  1368. #  endif /* TIOCNOTTY */
  1369. # endif /* BSD */
  1370. # if !defined(BSD) && !defined(TIOCNOTTY) && defined(SYSV)
  1371.         setpgrp();
  1372.         if (fork() != 0)
  1373.             exit(0);
  1374. # endif /* !BSD && !TIOCNOTTY && SYSV */
  1375. #endif /* XPG3 */
  1376.         errno = 0;
  1377.     }
  1378.  
  1379. #ifdef LOG
  1380.     if (LogLevel > 11)
  1381.         syslog(LOG_DEBUG, "in background, pid=%d", getpid());
  1382. #endif /* LOG */
  1383.  
  1384.     errno = 0;
  1385. }
  1386.